package com.rslai.base.tool.servertest.response;

import org.custommonkey.xmlunit.Difference;
import org.custommonkey.xmlunit.DifferenceListener;
import org.custommonkey.xmlunit.NodeDetail;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.util.List;

public class IgnoreUndefinedNodeDiffListener implements DifferenceListener {
    private List<String> differents;

    public IgnoreUndefinedNodeDiffListener(List<String> differents) {
        this.differents = differents;
    }

    public int differenceFound(Difference difference) {
        if (isIgnoreDifference(difference)) {
            return 2;
        }
        return 0;
    }

    private boolean isIgnoreDifference(Difference difference) {
        if ((ignoreAttributes(difference)) || (ignoreChildren(difference))) {
            return true;
        }
        return false;
    }

    private boolean ignoreChildren(Difference difference) {
        int differenceId = difference.getId();
        if ((differenceId != 19) && (differenceId != 10) && (differenceId != 22)) {
            return false;
        }
        NodeDetail controlNodeDetail = difference.getControlNodeDetail();
        NodeDetail testNodeDetail = difference.getTestNodeDetail();
        Node controlNode = controlNodeDetail.getNode();
        if (controlNode == null) return true;
        NodeList controlChildren = controlNode.getChildNodes();
        NodeList testChildren = testNodeDetail.getNode().getChildNodes();
        if (differenceId == 19) {
            int testChildrenLength = testChildren.getLength();
            int controlChildrenLength = controlChildren.getLength();
            boolean result = testChildrenLength >= controlChildrenLength;
            if (!result) {
                String message = String.format("期望有 %s 个节点,实际是 %s\n", new Object[]{Integer.valueOf(controlChildrenLength), Integer.valueOf(testChildrenLength)});
                String expected = String.format("期望的为: %s", new Object[]{description(controlChildren)});
                String actual = String.format("实际的为: %s", new Object[]{description(testChildren)});
                this.differents.add(new StringBuilder().append(message).append(expected).append(actual).toString());
            }
            return result;
        }
        if ((differenceId == 22) || (differenceId != 10)) {
            int length = controlChildren.getLength();
            int i = 0;
            if (i < length) {
                Node node = controlChildren.item(i);
                return hasNode(testChildren, node);
            }
        }
        return false;
    }

    private String description(NodeList controlChildren) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < controlChildren.getLength(); i++) {
            sb.append(new StringBuilder().append(controlChildren.item(i).toString()).append("\n").toString());
        }
        return sb.toString();
    }

    private boolean hasNode(NodeList testChildren, Node controlNode) {
        int length = testChildren.getLength();
        for (int i = 0; i < length; i++) {
            if (testChildren.item(i).getNodeName().equalsIgnoreCase(controlNode.getNodeName())) {
                return true;
            }
        }
        this.differents.add(String.format("期望存在节点 %s,但是实际输出中不存在", new Object[]{controlNode.toString()}));
        return false;
    }

    private boolean ignoreAttributes(Difference difference) {
        int differenceId = difference.getId();
        if ((differenceId != 11) && (differenceId != 2) && (differenceId != 3)) {
            return false;
        }
        NodeDetail controlNodeDetail = difference.getControlNodeDetail();
        NodeDetail testNodeDetail = difference.getTestNodeDetail();
        NamedNodeMap controlAttributes = controlNodeDetail.getNode().getAttributes();
        NamedNodeMap testAttributes = testNodeDetail.getNode().getAttributes();
        if (differenceId == 11) {
            int controlAttributesLen = controlAttributes.getLength();
            int testAttributesLen = testAttributes.getLength();
            boolean result = testAttributesLen >= controlAttributesLen;
            if (!result) {
                String message = String.format("期望有 %s 个属性,实际是 %s\n", new Object[]{Integer.valueOf(controlAttributesLen), Integer.valueOf(testAttributesLen)});
                String expected = String.format("期望的为: %s", new Object[]{description(controlAttributes)});
                String actual = String.format("实际的为: %s", new Object[]{description(testAttributes)});
                this.differents.add(new StringBuilder().append(message).append(expected).append(actual).toString());
            }
            return result;
        }
        if (differenceId == 2) {
            int len = controlAttributes.getLength();
            for (int i = 0; i < len; i++) {
                Node item = controlAttributes.item(i);
                Node testAttribute = testAttributes.getNamedItem(item.getNodeName());
                if (testAttribute == null) {
                    this.differents.add(String.format("期望存在属性 %s,但是实际输出中不存在", new Object[]{item.toString()}));
                    return false;
                }
            }
            return true;
        }
        if (differenceId == 3) {
            this.differents.add(String.format("期望在 %s 位置的值是 %s,但实际得到的是 %s", new Object[]{controlNodeDetail.getXpathLocation(), controlNodeDetail.getValue(), testNodeDetail.getValue()}));
        }

        return false;
    }

    private String description(NamedNodeMap controlAttributes) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < controlAttributes.getLength(); i++) {
            Node item = controlAttributes.item(i);
            sb.append(new StringBuilder().append(item.toString()).append("\n").toString());
        }
        return sb.toString();
    }

    public void skippedComparison(Node node, Node node1) {
    }

}
